D:\a\scloud-dns\scloud-dns\src\dns\resolver\mod.rs
Line | Count | Source |
1 | | pub(crate) mod stub; |
2 | | |
3 | | use crate::dns::packet::additional::AdditionalSection; |
4 | | use crate::dns::packet::answer::AnswerSection; |
5 | | use crate::dns::packet::authority::AuthoritySection; |
6 | | use crate::dns::packet::question::QuestionSection; |
7 | | use crate::exceptions::SCloudException; |
8 | | |
9 | | /// Check that each question has at least one corresponding record |
10 | | /// in the answer, authority, or additional sections. |
11 | | /// |
12 | | /// This prevents responses that do not actually answer the query. |
13 | | /// |
14 | | /// # Exemple : |
15 | | /// ``` |
16 | | /// use crate::dns::resolver::check_answer_diff; |
17 | | /// use crate::dns::packet::question::QuestionSection; |
18 | | /// use crate::dns::packet::answer::AnswerSection; |
19 | | /// use crate::dns::q_type::DNSRecordType; |
20 | | /// use crate::dns::q_class::DNSClass; |
21 | | /// |
22 | | /// let questions = vec![QuestionSection { |
23 | | /// q_name: "example.com".to_string(), |
24 | | /// q_type: DNSRecordType::A, |
25 | | /// q_class: DNSClass::IN, |
26 | | /// }]; |
27 | | /// |
28 | | /// let answers = vec![AnswerSection { |
29 | | /// q_name: "example.com".to_string(), |
30 | | /// r_type: DNSRecordType::A, |
31 | | /// r_class: DNSClass::IN, |
32 | | /// ttl: 300, |
33 | | /// rdlength: 4, |
34 | | /// rdata: vec![93, 184, 216, 34], |
35 | | /// }]; |
36 | | /// |
37 | | /// assert!(check_answer_diff(&questions, &answers, &[], &[]).is_ok()); |
38 | | /// ``` |
39 | 1 | pub(crate) fn check_answer_diff( |
40 | 1 | questions: &[QuestionSection], |
41 | 1 | answers: &[AnswerSection], |
42 | 1 | authorities: &[AuthoritySection], |
43 | 1 | additionals: &[AdditionalSection], |
44 | 1 | ) -> Result<(), SCloudException> { |
45 | 1 | for q in questions { |
46 | 1 | let found_in_answers = answers |
47 | 1 | .iter() |
48 | 1 | .any(|a| a.q_name == q.q_name0 && a.r_class == q.q_class0 ); |
49 | 1 | let found_in_authorities = authorities |
50 | 1 | .iter() |
51 | 1 | .any(|a| a.q_name == q.q_name && a.q_class == q.q_class); |
52 | 1 | let found_in_additionals = additionals |
53 | 1 | .iter() |
54 | 1 | .any(|a| a.q_name == q.q_name0 && a.q_class == q.q_class0 ); |
55 | | |
56 | 1 | if !found_in_answers && !found_in_authorities && !found_in_additionals0 { |
57 | 0 | return Err(SCloudException::SCLOUD_RESOLVER_ANSWER_MISMATCH); |
58 | 1 | } |
59 | | } |
60 | | |
61 | 1 | Ok(()) |
62 | 1 | } |
63 | | |
64 | | /// Ensure that authority records belong to the same zone |
65 | | /// as the original DNS questions. |
66 | | /// |
67 | | /// This prevents out-of-zone NS records. |
68 | | /// |
69 | | /// # Exemple : |
70 | | /// ``` |
71 | | /// use crate::dns::resolver::check_authority_diff; |
72 | | /// use crate::dns::packet::question::QuestionSection; |
73 | | /// use crate::dns::packet::authority::AuthoritySection; |
74 | | /// use crate::dns::q_type::DNSRecordType; |
75 | | /// use crate::dns::q_class::DNSClass; |
76 | | /// |
77 | | /// let questions = vec![QuestionSection { |
78 | | /// q_name: "example.com".to_string(), |
79 | | /// q_type: DNSRecordType::NS, |
80 | | /// q_class: DNSClass::IN, |
81 | | /// }]; |
82 | | /// |
83 | | /// let authorities = vec![AuthoritySection { |
84 | | /// q_name: "example.com".to_string(), |
85 | | /// q_type: DNSRecordType::NS, |
86 | | /// q_class: DNSClass::IN, |
87 | | /// ttl: 3600, |
88 | | /// ns_name: "ns1.example.com".to_string(), |
89 | | /// }]; |
90 | | /// |
91 | | /// assert!(check_authority_diff(&questions, &authorities).is_ok()); |
92 | | /// ``` |
93 | | #[allow(unused)] |
94 | 0 | pub(crate) fn check_authority_diff( |
95 | 0 | questions: &[QuestionSection], |
96 | 0 | authorities: &[AuthoritySection], |
97 | 0 | ) -> Result<(), SCloudException> { |
98 | 0 | for record in authorities.iter() { |
99 | 0 | if !questions.iter().any(|q| record.q_name == q.q_name) { |
100 | 0 | return Err(SCloudException::SCLOUD_RESOLVER_RECORD_OUT_OF_ZONE); |
101 | 0 | } |
102 | | } |
103 | 0 | Ok(()) |
104 | 0 | } |
105 | | |
106 | | /// Ensure that additional records correspond to the original questions. |
107 | | /// |
108 | | /// This is commonly used to validate glue records. |
109 | | /// |
110 | | /// # Exemple : |
111 | | /// ``` |
112 | | /// use crate::dns::resolver::check_additional_diff; |
113 | | /// use crate::dns::packet::question::QuestionSection; |
114 | | /// use crate::dns::packet::additional::AdditionalSection; |
115 | | /// use crate::dns::q_type::DNSRecordType; |
116 | | /// use crate::dns::q_class::DNSClass; |
117 | | /// |
118 | | /// let questions = vec![QuestionSection { |
119 | | /// q_name: "example.com".to_string(), |
120 | | /// q_type: DNSRecordType::A, |
121 | | /// q_class: DNSClass::IN, |
122 | | /// }]; |
123 | | /// |
124 | | /// let additionals = vec![AdditionalSection { |
125 | | /// q_name: "example.com".to_string(), |
126 | | /// q_type: DNSRecordType::A, |
127 | | /// q_class: DNSClass::IN, |
128 | | /// ttl: 300, |
129 | | /// rdlength: 4, |
130 | | /// rdata: vec![192, 0, 2, 1], |
131 | | /// }]; |
132 | | /// |
133 | | /// assert!(check_additional_diff(&questions, &additionals).is_ok()); |
134 | | /// ``` |
135 | | #[allow(unused)] |
136 | 0 | pub(crate) fn check_additional_diff( |
137 | 0 | questions: &[QuestionSection], |
138 | 0 | additionals: &[AdditionalSection], |
139 | 0 | ) -> Result<(), SCloudException> { |
140 | 0 | for record in additionals.iter() { |
141 | 0 | if !questions.iter().any(|q| record.q_name == q.q_name) { |
142 | 0 | return Err(SCloudException::SCLOUD_RESOLVER_RECORD_OUT_OF_ZONE); |
143 | 0 | } |
144 | | } |
145 | 0 | Ok(()) |
146 | 0 | } |